package com.weilus.util;
/*
 * Copyright (C) 2015 The lldq Project
 * All right reserved.
 * author: ltaiq@sina.com
 */
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

/**
 * 验证码生成器
 * 
 */
public class ImageValidCode {
		// 图片的宽度。
		private int width = 100;
		// 图片的高度。
		private int height = 35;
		// 验证码字符个数
		private int codeCount = 4;

		// 验证码
		private String code = null;
		// 验证码图片Buffer
		private BufferedImage buffImg = null;

		private char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
				'I', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
				'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9' };

		// 生成随机数
		private Random random = new Random();

		public ImageValidCode() {
			this.createCode();
		}

		/**
		 * 
		 * @param width
		 *            图片宽
		 * @param height
		 *            图片高
		 */
		public ImageValidCode(int width, int height) {
			this.width = width;
			this.height = height;
			this.createCode();
		}

		/**
		 * 
		 * @param width
		 *            图片宽
		 * @param height
		 *            图片高
		 * @param codeCount
		 *            字符个数
		 * @param lineCount
		 *            干扰线条数
		 */
		public ImageValidCode(int width, int height, int codeCount, int lineCount) {
			this.width = width;
			this.height = height;
			this.codeCount = codeCount;
			this.createCode();
		}

		public void createCode() {
			int codeX = 0;
			int fontHeight = 0;
			fontHeight = height - 5;// 字体的高度
			codeX = width / (codeCount+1);// 每个字符的宽度

			// 图像buffer
			buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
			Graphics2D g = buffImg.createGraphics();

			// 将图像填充为白色
			g.setColor(Color.WHITE);
			g.fillRect(0, 0, width, height);

			// 创建字体
			Font font =new Font("Fixedsys", Font.PLAIN, fontHeight);
			g.setFont(font);
			// 绘制干扰线
			drawThickLine(g, 0, random.nextInt(height) + 1,width, random.nextInt(height) + 1, 4, getRandomColor());// 加一道线
			shear(g, buffImg.getWidth()-5, buffImg.getHeight()-5, Color.WHITE);
			StringBuffer randomCode = new StringBuffer();
			// 随机产生验证码字符
			for (int i = 0; i < codeCount; i++) {
				String strRand = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]);
				// 设置字体颜色
				g.setColor(getRandomColor());
				g.setFont(font);
				// 设置字体位置
				g.drawString(strRand, i * codeX+5,getRandomNumber(10)+height-10);
				randomCode.append(strRand);
			}
			
			code = randomCode.toString();
		}

		/** 获取随机颜色 */
		private Color getRandomColor() {
			return new Color(248, 71, 15);
		}

		/** 获取随机数 */
		private int getRandomNumber(int number) {
			return random.nextInt(number);
		}
		public void write(String path) throws IOException {
			OutputStream sos = new FileOutputStream(path);
			this.write(sos);
		}

		public void write(OutputStream sos) throws IOException {
			ImageIO.write(buffImg, "png", sos);
		}

		public BufferedImage getBuffImg() {
			return buffImg;
		}

		public String getCode() {
			return code;
		}

	
		// 画一道粗线的方法
		private void drawThickLine(Graphics g, int x1, int y1, int x2, int y2,
				int thickness, Color c) {

			g.setColor(c);
			int dX = x2 - x1;
			int dY = y2 - y1;
			double lineLength = Math.sqrt(dX * dX + dY * dY);

			double scale = (double) (thickness) / (2 * lineLength);

			double ddx = -scale * (double) dY;
			double ddy = scale * (double) dX;
			ddx += (ddx > 0) ? 0.5 : -0.5;
			ddy += (ddy > 0) ? 0.5 : -0.5;
			int dx = (int) ddx;
			int dy = (int) ddy;

			int xPoints[] = new int[4];
			int yPoints[] = new int[4];

			xPoints[0] = x1 + dx;
			yPoints[0] = y1 + dy;
			xPoints[1] = x1 - dx;
			yPoints[1] = y1 - dy;
			xPoints[2] = x2 - dx;
			yPoints[2] = y2 - dy;
			xPoints[3] = x2 + dx;
			yPoints[3] = y2 + dy;
			shear(g, dx, dy, c);
			g.fillPolygon(xPoints, yPoints, 4);
		}
		// 扭曲方法
		private void shear(Graphics g, int w1, int h1, Color color) {
			shearX(g, w1, h1, color);
			shearY(g, w1, h1, color);
		}

		private void shearX(Graphics g, int w1, int h1, Color color) {

			int period = random.nextInt(2);

			boolean borderGap = true;
			int frames = 1;
			int phase = random.nextInt(2);

			for (int i = 0; i < h1; i++) {
				double d = (double) (period >> 1)
						* Math.sin((double) i / (double) period
								+ (6.2831853071795862D * (double) phase)
								/ (double) frames);
				g.copyArea(0, i, w1, 1, (int) d, 0);
				if (borderGap) {
					g.setColor(color);
					g.drawLine((int) d, i, 0, i);
					g.drawLine((int) d + w1, i, w1, i);
				}
			}

		}

		private void shearY(Graphics g, int w1, int h1, Color color) {

			int period = random.nextInt(30) + 10; // 50;

			boolean borderGap = true;
			int frames = 20;
			int phase = 7;
			for (int i = 0; i < w1; i++) {
				double d = (double) (period >> 1)
						* Math.sin((double) i / (double) period
								+ (6.2831853071795862D * (double) phase)
								/ (double) frames);
				g.copyArea(i, 0, 1, h1, 0, (int) d);
				if (borderGap) {
					g.setColor(color);
					g.drawLine(i, (int) d, i, 0);
					g.drawLine(i, (int) d + h1, i, h1);
				}

			}

		}

	}
